<?php

namespace app\common\components;

use think\contract\LogHandlerInterface;
use think\Exception;
use think\Model;
use think\App;

class LogMysql implements LogHandlerInterface
{
    private $_model;
    /**
     * 配置参数
     * @var array
     */
    protected $config = [
        'time_format'  => 'c',
        'json'         => false,
        'json_options' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES,
        'format'       => '[%s][%s] %s',

        'class'        => null,
        'expire'       => 7 * 24 * 3600,
        'percent'      => 15     //百分之15几率会清理日志(保留10000条, 保留7天之内的日志)
    ];

    // 实例化并传入参数
    public function __construct($config = [])
    {
        if (is_array($config)) {
            $this->config = array_merge($this->config, $config);
        }

        if (empty($this->config['format'])) {
            $this->config['format'] = '[%s][%s] %s';
        }

        if (empty($this->config['class']) || !class_exists($this->config['class'])) {
            throw new Exception(__CLASS__ . 'class 参数配置错误.');
        }

        $model = new $this->config['class'];
        if (!($model instanceof Model)){
            throw new Exception('param class 必须是'.Model::class.'子类');
        }
        $this->_model = $model;

    }

    /**
     * 日志写入接口
     * @param array $log
     * @return bool
     * @throws Exception
     */
    public function save(array $log) : bool{

        $info = [];

        // 日志信息封装
        $time = date($this->config['time_format']);

        //生成日志信息
        foreach ($log as $type => $val) {
            $message = [];
            foreach ($val as $msg) {
                if (!is_string($msg)) {
                    $msg = var_export($msg, true);
                }

                $message[] = $this->config['json'] ?
                    json_encode(['time' => $time, 'type' => $type, 'msg' => $msg], $this->config['json_options']) :
                    sprintf($this->config['format'], $time, $type, $msg);
            }


            $info[$type] = $message;
        }

        if ($info) {
            return $this->write($info);
        }

        return true;
    }

    /**
     * 日志写入
     * @param array $message
     * @return bool
     * @throws \Exception
     */
    protected function write(array $message): bool
    {
        //触发清理日志程序
        $this->clearLog();

        $info = [];

        foreach ($message as $type => $msg) {
            $info[] = [
                'type' => $type,
                'log' => is_array($msg) ? implode(PHP_EOL, $msg) : $msg,
                'route' => request()->completePathInfo(true),
                'data'  => jsonStr(input()),
                'user_id' => app()->user->isGuest() ? null : app()->user->getId()
            ];
        }

        return (bool) $this->_model->saveAll($info);
    }

    /**
     * 一定概率触发日志清理城西
     */
    protected function clearLog(){
        if(mt_rand(1,100) > $this->config['percent']){
            return;
        }

        $class = $this->config['class'];
        $class::destroy(function($query) use ($class){
            $query->where('create_time','<',(time() - $this->config['expire']));
        });
        return;
    }


}